/*******************************************************************************
 * Copyright (c) 2002 Boris Pruessmann and others. All rights reserved. This
 * program and the accompanying materials are made available under the terms of
 * the Common Public License v0.5 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.action;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.IResolveResult;
import net.sourceforge.perforce.core.api.ResolveTypeEnum;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.core.resources.IP4File;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.dialogs.AutoResolveDialog;
import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.team.core.TeamException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class AutoResolveAction extends P4FileAction {
  //----------------------------------------------------------------------------
  // -- Public Methods

  @Override
  public void run(IAction action) {
    final IP4File[] files = getSelectedPerforceFiles();
    boolean enableReResolve = shouldEnableReResolve(files);

    AutoResolveDialog dialog = new AutoResolveDialog(getShell(), enableReResolve);
    if (dialog.open() != AutoResolveDialog.OK) {
      return;
    }

    int tempOptions = (dialog.shouldReResolve()) ? IPerforceServer.RESOLVE_FORCE : 0;
    tempOptions &= (dialog.shouldAttemptBinaryMerge()) ? IPerforceServer.RESOLVE_MERGE_BINARY : 0;

    final Set<IP4File> skippedFiles = Sets.newHashSet();
    final ResolveTypeEnum resolveType = dialog.getResolveType();
    final int options = tempOptions;
    run(new WorkspaceModifyOperation() {
      @Override
      public void execute(IProgressMonitor monitor) throws InvocationTargetException {
        monitor = Policy.monitorFor(monitor);
        monitor.beginTask("", files.length * 1000); //$NON-NLS-1$

        Set<IPerforceServer> serverSet = Sets.newHashSet();
        List<IPath> resolvedFiles = Lists.newArrayList();
        try {
          for (int i = 0; i < files.length && !monitor.isCanceled(); i++) {
            IP4File file = files[i];
            monitor.subTask(Policy.bind("AutoResolveAction.Resolving", //$NON-NLS-1$
                file.getName()));

            IPerforceServer server = file.getServer();
            IResolveResult[] resolveResults =
                server.resolve(file.getDepotFilename(), resolveType, options);

            Policy.assertTrue(resolveResults.length == 1);
            if (resolveResults[0].isSkipped()) {
              skippedFiles.add(file);
            } else {
              serverSet.add(server);
              resolvedFiles.add(file.getLocation());
            }

            monitor.worked(500);
          }
        } catch (PerforceException e) {
          throw new InvocationTargetException(e);
        } finally {
          try {
            IWorkspaceRoot root = PerforceUIPlugin.getWorkspace().getRoot();
            for (Iterator<IPath> it = resolvedFiles.iterator(); it.hasNext();) {
              IPath location = it.next();
              IFile file = root.getFileForLocation(location);
              if (file != null) {
                P4TeamProvider provider = P4TeamProvider.getProvider(file);

                file.refreshLocal(IFile.DEPTH_ZERO, null);
                provider.refreshState(new IFile[] {file}, IFile.DEPTH_ZERO, null);
              }

              monitor.worked(500);
            }
          } catch (TeamException e) {
            PerforceUIPlugin.log(e.getStatus());
          } catch (CoreException e) {
            PerforceUIPlugin.log(e.getStatus());
          }

          IPerforceServer[] servers = serverSet.toArray(new IPerforceServer[serverSet.size()]);
          PerforceCorePlugin.getPlugin().broadcastChangelistStateChanges(servers);

          monitor.done();
        }
      }
    }, PROGRESS_DIALOG);

    Integer resolved = new Integer(files.length - skippedFiles.size());
    String message = Policy.bind("AutoResolveAction.statusMessage", resolved); //$NON-NLS-1$
    MultiStatus status = new MultiStatus(PerforceUIPlugin.ID, MultiStatus.INFO, message, null);
    for (IP4File file : skippedFiles) {
      message = Policy.bind("AutoResolveAction.wasSkipped", file.getDepotFilename()); //$NON-NLS-1$
      status.merge(new Status(Status.INFO, PerforceUIPlugin.ID, 0, message, null));
    }

    String title = Policy.bind("AutoResolveAction.statusTitle"); //$NON-NLS-1$
    if (status.isOK()) {
      MessageDialog.openInformation(getShell(), title, status.getMessage());
    } else {
      ErrorDialog.openError(getShell(), title, Policy.bind("AutoResolveAction.statusErrorMessage"), //$NON-NLS-1$
          status);
    }
  }

  // ---------------------------------------------------------------------------
  // Protected Methods

  @SuppressWarnings("unused")
  // PerforceException
  @Override
  protected boolean isEnabled() throws PerforceException {
    IP4File[] files = getSelectedPerforceFiles();
    for (int i = 0; i < files.length; i++) {
      IP4File file = files[i];
      if (!file.needsResolve()) {
        return false;
      }
    }

    return true;
  }

  //----------------------------------------------------------------------------
  // - Private Methods

  /**
   * Checks whether any of the given files already has been resolved. In that
   * case, we want to enable the re-resolve button of the AutoResolveDialog.
   * 
   * @param files array of IP4File to check
   * @return true or false
   */
  private boolean shouldEnableReResolve(IP4File[] files) {
    for (int i = 0; i < files.length; i++) {
      if (files[i].isResolved()) {
        return true;
      }
    }

    return false;
  }
}
